package edu.cmu.ece.ds.droidchat.model;

import java.math.BigInteger;
import java.security.InvalidKeyException;
import java.security.Key;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.KeyGenerator;
import javax.crypto.NoSuchPaddingException;

/*
 * this is the data structure that records all the information of a chat session
 * each user should keep one copy of this when enter or create a chat session
 */

public class ChatSessionInfo {

    /*
     * following three are for keys actually symmetric key.
     */
    private static String algorithm = "DESede";

    // used to decrypt/encrypt chat messages
    // for this chat session
    private Cipher cipher = null;

    // chat session id, different from login session id....
    // identifies a chat session
    private String sessionid;

    // the username of all the participants
    // (should we store the ips here?)
    public ArrayList<String> participants;

    private boolean pending = true;

    // the username of the latest invitee
    private String username;
    // the latest invitee's user's public key
    private BigInteger publicModulus;
    private BigInteger publicExponent;

    private String chatSessionName = "no name yet";

    /*
     * for creator, we don't have keys, so constructor will create that for
     * others, they will receive those things and no need to create
     */
    public ChatSessionInfo(String selfUsername, LoginSessionAttribute login){
    	
    	try {
			this.key = KeyGenerator.getInstance(algorithm).generateKey();
			this.cipher =Cipher.getInstance(algorithm);		
		} catch (NoSuchAlgorithmException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchPaddingException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
        
        if (login != null) {
            this.sessionid = login.getUsername() + login.getChatsessionnum();
        } else {
        	// for Dennis facebook
        	this.sessionid = Double.toString(Math.random());
        }
        participants = new ArrayList<String>();
        participants.add(selfUsername);
    }

    public ChatSessionInfo(LoginSessionAttribute login) {
    	this.key = null;
        this.cipher = null;
        if (login != null) {
            this.sessionid = login.getUsername() + login.getChatsessionnum();
        } else {
        	// for Dennis facebook
        	this.sessionid = Double.toString(Math.random());
        }
        participants = new ArrayList<String>();
        participants.add("null");
	}
    
    /*
     * This constructor is intended to be called by the chat session creator.
     * Chat session key is generated
     */
    /*
     * public ChatSessionInfo(String id,String self,String receiver) throws
     * NoSuchAlgorithmException, NoSuchPaddingException{ this.key =
     * KeyGenerator.getInstance(algorithm).generateKey(); this.cipher =
     * Cipher.getInstance(algorithm); this.sessionid=id; participants=new
     * ArrayList<String>(); participants.add(self); participants.add(receiver);
     * }
     */

    /*
     * This constructor is intended to be called by the the users being invited
     * to join a chat session. Chat session key not generated
     */
    /*
     * public ChatSessionInfo(Key key, Cipher cipher,String id) throws
     * NoSuchAlgorithmException, NoSuchPaddingException{ if(key!=null &&
     * cipher!=null) { this.key=key; this.cipher=cipher; } this.sessionid=id;
     * participants=new ArrayList<String>(); }
     */

    /*
     * following are encrypt and decrypt functions given a plaintext or cypher,
     * return the other thing
     */

	public byte[] encrypt(String input) throws InvalidKeyException,
            BadPaddingException, IllegalBlockSizeException {
        cipher.init(Cipher.ENCRYPT_MODE, key);
        byte[] inputBytes = input.getBytes();
        return cipher.doFinal(inputBytes);
    }

    public String decrypt(byte[] encryptionBytes) throws InvalidKeyException,
            BadPaddingException, IllegalBlockSizeException {
        cipher.init(Cipher.DECRYPT_MODE, key);
        byte[] recoveredBytes = cipher.doFinal(encryptionBytes);
        String recovered = new String(recoveredBytes);
        return recovered;
    }

    public Key getKey() {
        return key;
    }

    public Cipher getCipher() {
        return cipher;
    }

    // returns the chat session id for this chat session
    public String getSessionid() {
        return sessionid;
    }

    public BigInteger getPublicModulus() {
        return publicModulus;
    }

    public BigInteger getPublicExponent() {
        return publicExponent;
    }

    public String getUsername() {
        return username;
    }

    public void setPublicExponent(BigInteger publicExponent) {
        this.publicExponent = publicExponent;
    }

    public void setPublicModulus(BigInteger publicModulus) {
        this.publicModulus = publicModulus;
    }

    public void setUsername(String username) {
        this.username = username;
    }

    private Key key = null; // the chat session key,

    public boolean isPending() {
        return pending;
    }

    public void setPending(boolean pending) {
        this.pending = pending;
    }

    public void setKey(Key key) {
        this.key = key;
    }

    public void setCipher(Cipher cipher) {
        this.cipher = cipher;
    }

    public ArrayList<String> getParticipants() {
        return participants;
    }

    public void setParticipants(ArrayList<String> participants) {
        this.participants = participants;
    }

    public String getChatSessionName() {
        return chatSessionName;
    }

    public void setChatSessionName(String chatSessionName) {
        this.chatSessionName = chatSessionName;
    }
    
    public void addParticipant(String username){
    	this.participants.add(username);
    }
}
